package com.fc.codegen.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.fc.codegen.dto.GenModuleDto;
import com.fc.codegen.entity.ColumnEntity;
import com.fc.codegen.entity.GenConfig;
import com.fc.codegen.entity.GenFormConf;
import com.fc.codegen.entity.TableEntity;
import com.fc.codegen.service.GenModuleCodeService;
import com.fc.common.core.constant.CommonConstants;
import com.fc.common.core.exception.CheckedException;
import lombok.SneakyThrows;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.generic.DateTool;
import org.apache.velocity.tools.generic.MathTool;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipOutputStream;

/**
 * @Description:
 * @ClassName: GenModuleCodeServiceImpl
 * @Author: weisn
 * @Date: 2023/2/7 15:35
 * @Version: 1.0
 */
@Service(value = "genModuleCodeService")
public class GenModuleCodeServiceImpl implements GenModuleCodeService {



    @SneakyThrows
    @Override
    public Map<String, String> gen(GenModuleDto genModule, ZipOutputStream zip) {
        // 模板入参
        Map<String, Object> tempModel = buildTempModel(genModule);
        return renderData(genModule,zip, tempModel);
    }

    Map<String, Object> buildTempModel(GenModuleDto genModule) throws ConfigurationException {
        // 封装模板数据
        Map<String, Object> map = new HashMap<>(16);
        map.put("proName", genModule.getProName());
        map.put("moduleNameHump", genModule.getModuleName().substring(0,1).toUpperCase() + genModule.getModuleName().substring(1));
        map.put("moduleName", genModule.getModuleName());
        map.put("packageStructure", genModule.getPackageStructure());
        Configuration configuration = new PropertiesConfiguration("generator.properties");
        map.put("author", configuration.getString("author"));
        map.put("groupId", genModule.getGroupId());
        map.put("versions", genModule.getVersions());
        return map;
    }




    /**
     * 渲染数据
     * @param genModule 用户输入相关
     * @param zip 输出zip流
     * @param map
     */
    @SneakyThrows
    Map<String, String> renderData(GenModuleDto genModule, ZipOutputStream zip, Map<String, Object> map) {
        // 设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);

        VelocityContext context = new VelocityContext(map);
        // 函数库
        context.put("math", new MathTool());
        context.put("dateTool", new DateTool());

        // 获取模板列表
        List<String> templates = getTemplates();
        Map<String, String> resultMap = new LinkedHashMap<>(8);

        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            try {
                Template tpl = Velocity.getTemplate(template, CharsetUtil.UTF_8);
                tpl.merge(context, sw);
            } catch (Exception e) {
                System.out.println(template);
                e.printStackTrace();
            }

            // 添加到zip
            String fileName = getFileName(template, genModule,map);

            if (zip != null) {
                try {
                    zip.putNextEntry(new ZipEntry(Objects.requireNonNull(fileName)));
                    IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
                    IoUtil.close(sw);
                }
                catch (ZipException zipException) {
                }
                zip.closeEntry();
            }
            resultMap.put(template, sw.toString());
        }

        return resultMap;
    }

    /**
     * 注入支持的模板列表
     * @return ListString
     */
    List<String> getTemplates() {
        List<String> templates = new ArrayList<>();
        templates.add("template/module/pom.xml.vm");
        templates.add("template/module/api/pom.xml.vm");
        templates.add("template/module/api/package-info.java.vm");
        templates.add("template/module/biz/Application.java.vm");
        templates.add("template/module/biz/application.yml.vm");
        templates.add("template/module/biz/logback-spring.xml.vm");
        templates.add("template/module/biz/package-info.java.vm");
        templates.add("template/module/biz/pom.xml.vm");
        return templates;
    }

    /**
     * 获取文件名
     */
    String getFileName(String template, GenModuleDto genModule, Map<String, Object> map) {
        String packagePath = genModule.getModuleName();
        if (template.contains("template/module/pom.xml.vm")) {
            return packagePath + File.separator + "pom.xml";
        }
        if (template.contains("template/module/api/pom.xml.vm")) {
            return packagePath + File.separator + genModule.getModuleName() + "-api" + File.separator  + "pom.xml";
        }

        if (template.contains("template/module/api/package-info.java.vm")) {
            return packagePath + File.separator + genModule.getModuleName() + "-api" + File.separator + "src\\main\\java\\" + genModule.getPackageStructure().replace(".","\\") + "\\feign"  + "package-info.java";
        }
        if (template.contains("template/module/biz/Application.java.vm")) {
            return packagePath + File.separator + genModule.getModuleName() + "-biz" + File.separator + "src\\main\\java\\" + genModule.getPackageStructure().replace(".","\\")  + "\\" + map.get("moduleNameHump") + "Application.java";
        }
        if (template.contains("template/module/biz/package-info.java.vm")) {
            return packagePath + File.separator + genModule.getModuleName() + "-biz" + File.separator + "src\\main\\java\\" + genModule.getPackageStructure().replace(".","\\")  + "\\controller\\" + "package-info.java";
        }
        if (template.contains("template/module/biz/application.yml.vm")) {
            return packagePath + File.separator + genModule.getModuleName() + "-biz" + File.separator + "src\\main\\resources\\" +  "application.yml";
        }
        if (template.contains("template/module/biz/logback-spring.xml.vm")) {
            return packagePath + File.separator + genModule.getModuleName() + "-biz" + File.separator + "src\\main\\resources\\" +  "logback-spring.xml";
        }
        if (template.contains("template/module/biz/pom.xml.vm")) {
            return packagePath + File.separator + genModule.getModuleName() + "-biz" + File.separator  + "pom.xml";
        }
        return null;
    }
}
